package cn.demoncat.util.redis.util;

import cn.demoncat.util.redis.annotation.Lock;
import cn.demoncat.util.redis.entity.RedisLock;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.function.Supplier;

/**
 * Redis分布式锁工具
 *
 * 注：为了跟踪项目中使用了哪些锁，必须使用RedisLock对象来声明锁的缓存常量
 *
 * @see Lock	方法锁-快捷注解
 * @see RedissonUtil	更多锁操作
 *
 *
 * @author 延晓磊
 *
 * @since 2018年7月13日
 */
@Component
public class RedisLockUtil {

	@Resource
	private RedissonUtil redissonUtil;

	/**
	 * 可重入锁
	 *
	 * 场景：A获取锁开始执行 > B未获取锁，阻塞等待 > A执行完成，释放锁/锁到期 > B获取锁开始执行
	 *
	 * 1、阻塞加锁/尝试加锁
	 * 2、加锁成功：执行业务，解锁/自动释放锁
	 * 2、加锁失败：执行降级处理
	 *
	 * @param lock  锁（根据tryLock判断阻塞或尝试）
	 * @param success  获取锁后执行的操作
	 * @param error   未获取锁的降级处理，为空时直接返回null
	 *
	 * @return 业务返回结果/降级返回结果/null
	 *
	 * @author 延晓磊
	 * @since 2021年02月10日
	 */
	public <R>R lock(RedisLock lock, Supplier<R> success, Supplier<R> error){
		return redissonUtil.lock(lock, success, error);
	}

	/**
	 * 可重入锁 - 阻塞获取，顺序执行/间隔执行
	 *
	 * 场景：A获取锁开始执行 > B未获取锁，阻塞等待 > A执行完成，释放锁/锁到期 > B获取锁开始执行
	 *
	 * 1、阻塞加锁
	 * 2、执行业务
	 * 3、解锁/自动释放锁
	 *
	 * @param lock  锁（忽略tryLock属性）
	 * @param callable  获取锁后执行的操作
	 *
	 * @return 业务返回结果
	 *
	 * @author 延晓磊
	 * @since 2021年02月10日
	 */
	public <R>R lock(RedisLock lock, Supplier<R> callable){
		return redissonUtil.lock(lock, callable);
	}

	/**
	 * 可重入锁 - 阻塞获取，顺序执行/间隔执行
	 *
	 * 场景：A获取锁开始执行 > B未获取锁，阻塞等待 > A执行完成，释放锁/锁到期 > B获取锁开始执行
	 *
	 * 1、阻塞加锁
	 * 2、执行业务
	 * 3、解锁/自动释放锁
	 *
	 * @param lock  锁（忽略tryLock属性）
	 * @param runnable  获取锁后执行的操作
	 *
	 * @author 延晓磊
	 * @since 2021年02月10日
	 */
	public void lock(RedisLock lock, Runnable runnable){
		redissonUtil.lock(lock, () -> {
			// 执行回调
			runnable.run();
			// 返回空
			return null;
		});
	}

	/**
	 * 可重入锁 - 尝试获取，顺序执行/间隔执行
	 *
	 * 场景：A获取锁开始执行 > B未获取锁，放弃执行（降级处理） > A执行完成，释放锁/锁到期
	 *
	 * 1、尝试加锁
	 * 2、加锁成功：执行业务，解锁/自动释放锁
	 * 2、加锁失败：执行降级处理
	 *
	 * @param lock  锁（忽略tryLock属性）
	 * @param success  获取锁后执行的操作
	 * @param error   未获取锁的降级处理，为空时直接返回null
	 *
	 * @return 业务返回结果/降级返回结果/null
	 *
	 * @author 延晓磊
	 * @since 2021年02月10日
	 */
	public <R>R tryLock(RedisLock lock, Supplier<R> success, Supplier<R> error){
		return redissonUtil.tryLock(lock, success, error);
	}

	/**
	 * 可重入锁 - 尝试获取，顺序执行/间隔执行
	 *
	 * 场景：A获取锁开始执行 > B未获取锁，放弃执行 > A执行完成，释放锁/锁到期
	 *
	 * 1、尝试加锁，失败返回false
	 * 2、执行业务
	 * 3、解锁/自动释放锁
	 *
	 * @param lock  锁（忽略tryLock属性）
	 * @param runnable  获取锁后执行的操作
	 *
	 * @return 是否加锁成功
	 *
	 * @author 延晓磊
	 * @since 2021年02月10日
	 */
	public boolean tryLock(RedisLock lock, Runnable runnable){
		return redissonUtil.tryLock(lock, runnable);
	}



}
